package com.wanhong.springboot.ssm.framework.interceptor;

import com.wanhong.springboot.ssm.framework.annocation.IgnoreTokenAuth;
import com.wanhong.springboot.ssm.framework.constant.CommonConstant;
import com.wanhong.springboot.ssm.framework.constant.RedisKey;
import com.wanhong.springboot.ssm.framework.context.UserContextHandler;
import com.wanhong.springboot.ssm.framework.exception.BizException;
import com.wanhong.springboot.ssm.framework.exception.BizExceptionCodeEnum;
import com.wanhong.springboot.ssm.framework.jwt.JwtConstant;
import com.wanhong.springboot.ssm.framework.jwt.JwtUtil;
import com.wanhong.springboot.ssm.framework.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * @author w_yu
 * @date 2020/11/26 14:55
 * @desc
 */
@Slf4j
public class UserAuthInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private JwtConstant jwtConstant;
    @Autowired
    private RedisUtils redisUtils;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return super.preHandle(request, response, handler);
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        // 看类和方法上面，有没有被IgnoreTokenAuth 注解
        IgnoreTokenAuth ignoreTokenAuth = handlerMethod.getBeanType().getAnnotation(IgnoreTokenAuth.class);
        if (ignoreTokenAuth == null) {
            ignoreTokenAuth = handlerMethod.getMethodAnnotation(IgnoreTokenAuth.class);
        }
        // 如果被注解的话，就不校验权限
        if (ignoreTokenAuth != null) {
            return super.preHandle(request, response, handler);
        }
        String accessToken = request.getHeader(jwtConstant.tokenName);
        if (StringUtils.isBlank(accessToken)) {
            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if (cookie.getName().equals(jwtConstant.tokenName)) {
                        accessToken = cookie.getValue();
                        break;
                    }
                }
            }
        }
        if (StringUtils.isBlank(accessToken)) {
            throw new BizException(BizExceptionCodeEnum.TOKEN_ILLEGAL);
        }
        String validTime = redisUtils.get(RedisKey.getUserTokenKey(accessToken));
        if (StringUtils.isBlank(validTime)) {
            throw new BizException(BizExceptionCodeEnum.TOKEN_EXPIRE);
        }
        long currentTime = System.currentTimeMillis();
        //计算过期时间到当前时间的时间间隔
        long mills = (Long.valueOf(validTime) - currentTime) / 1000;
        //小于0说明已经过期，直接抛错
        if (mills <= 0) {
            throw new BizException(BizExceptionCodeEnum.TOKEN_EXPIRE);
        } else if (mills < jwtConstant.refreshInterval) {
            //小于刷新间隔，需要刷新token
            accessToken = jwtUtil.refreshToken(accessToken);
            redisUtils.set(RedisKey.getUserTokenKey(accessToken),
                    String.valueOf(new Date(currentTime + jwtConstant.expireTime * CommonConstant.LONG_ONE_THOUSAND).getTime()),
                    jwtConstant.expireTime);
        }
        UserContextHandler.set(jwtUtil.decodeToken(accessToken));
        response.setHeader(jwtConstant.tokenName, accessToken);
        //解析token，设置到ThreadLocal中
        return super.preHandle(request, response, handler);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) throws Exception {
        UserContextHandler.remove();
        super.afterCompletion(request, response, handler, ex);
    }
}
